import _thread
import gc

import ubinascii
import ujson as json
import uos as os
import urequests as requests
import utime as time
from machine import Timer, reset, unique_id
from umqtt.simple import MQTTClient


class Mqttclient():

    def __init__(self, config):
        self.config = config
        self.client = None
        self.keepalive_time = 300
        self.keepalive_i = 0
        self.listenTimer = Timer(-1)
        self.lastputtime = 0

        self.version = '0.0.2'
        self.version_file = self.config['version']
        try:
            os.stat(self.version_file)
            with open(self.version_file) as fp:
                self.version = fp.read()
        except Exception:pass
        self.version = self.version.strip()

        self.equipm_id = ''
        self.equipm_file = self.config['equipm']
        try:
            os.stat(self.equipm_file)
            with open(self.equipm_file) as fp:
                self.equipm_id = fp.read()
        except Exception:pass
        self.equipm_id = self.equipm_id.strip()

        device_name = ubinascii.hexlify(unique_id()).decode()
        self.esp_id = f"wnkg{str(device_name)}"
        self.config['mqtt']['clientid'] = str(self.esp_id)
        self.config['mqtt']['mqttname'] = str(self.esp_id)

        self.subtopic = f'/{self.esp_id}/wnkg/admin'
        self.puttopic = f'/{self.equipm_id}/equipm/admin'

    def reboot(self):
        reset()

    def thread_recv(self):
        while 1:
            try:
                self.client.check_msg()
                self.keepalive_i += 1
                if self.keepalive_i >= self.keepalive_time:
                    self.keepalive_i = 0
                    self.client.publish('/keepalive', '1', True, 1)
                    self.lastputtime = time.time()
                    gc.enable()
            except Exception as e:
                print('client.check_msg Error:', e)
                self.reboot()
            time.sleep_ms(100)


    def listen_conn(self, e):
        if self.lastputtime >0 and (time.time() - self.lastputtime) > 60:
            self.reboot()

    def connect(self):
        if not self.equipm_id:
            print("Error:万能开关还没有绑定到自美网关设备上")
            return False
        serverhost = self.config['mqtt']['host']
        serverport = self.config['mqtt']['port']
        clientid   = self.config['mqtt']['clientid']
        mqtt_user  = self.config['mqtt']['mqttname']
        mqtt_pass  = self.config['mqtt']['mqttpass']

        self.client = MQTTClient(clientid, serverhost, serverport, mqtt_user, mqtt_pass, keepalive=60)
        self.client.set_callback(self.set_callback)
        is_conn = False
        try:
            self.client.connect()
            self.client.subscribe(self.subtopic)
            self.online()
            print(f"MQTT连接成功,并订阅主题{self.subtopic}")
            is_conn = True
            _thread.start_new_thread(self.thread_recv,())
        except Exception as e:
            print("mqtt connect error", e)
        self.listenTimer.init(period=5000, mode=Timer.PERIODIC, callback=self.listen_conn)
        return is_conn

    def reconnect(self):
        i = 0
        while True:
            try:
                self.client.connect(False)
                return True
            except OSError as e:
                print("mqtt,reconnect: %r" % e)
                i += 1
                time.sleep(i)

    def online(self):
        self.send(Data={"type":'online', "deviceid":str( self.esp_id )})

    # 给用户自定义回调函数
    def receive(self, topic, rejson):
        pass

    # MQTT默认消息回调
    def set_callback(self, topic, msg):  # sourcery skip: use-contextlib-suppress
        json_obj = msg.decode("utf-8")
        try:
            json_obj = json.loads(json_obj)
            self.receive(topic, json_obj)
        except Exception:
            pass

    def publish(self, topic, msg, retain=False, qos=0):
        while True:
            try:
                return self.client.publish(topic, msg, retain, qos)
            except OSError as e:
                print("mqtt,publish: %r" % e)
            self.reconnect()
            time.sleep(1)

    def send(self, MsgType='Text', Receiver='WnkgProxy', Data=''):
        # sourcery skip: use-contextlib-suppress
        send_str = {"MsgType": MsgType, "Receiver": Receiver, "Data": Data, "Sender": str(self.esp_id)}
        json_str = json.dumps(send_str)
        try:
            self.client.publish(self.puttopic, json_str)
            del json_str, send_str
        except OSError:pass

    def main(self):  # sourcery skip: use-contextlib-suppress
        post_data = f'deviceid={str(self.esp_id)}&version={self.version}'
        http_url = self.config['httpapi'] + '/esp/online.html?' + post_data
        re_json = {'code': '9999'}
        try:
            r = requests.get(http_url)
            re_json = r.json()
        except Exception:
            return False
        if str(re_json['code']) == '0000':
            self.config['mqtt']['mqttpass'] = str(re_json['skey'])
            return self.connect()
